#import sys
from itertools import *
from string import ascii_letters, digits, punctuation
import hashlib
import MySQLdb


def combinations_with_replacement(iterable, r):
    # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC
    pool = tuple(iterable)
    n = len(pool)
    if not n and r:
        return
    indices = [0] * r
    yield tuple(pool[i] for i in indices)
    while True:
        for i in reversed(range(r)):
            if indices[i] != n - 1:
                break
        else:
            return
        indices[i:] = [indices[i] + 1] * (r - i)
        yield tuple(pool[i] for i in indices)


def getrec():
        # Open database connection
        db = MySQLdb.connect("nvidia1-crunchy", "root", "root", "hash")

        # prepare a cursor object using cursor() method
        cursor = db.cursor()

        # Prepare SQL query to INSERT a record into the database.
        sql = "SELECT idmd5,start, stop, KeyL FROM md5 WHERE Done = \
                'false' LIMIT 1"

        #try:
           # Execute the SQL command
        cursor.execute(sql)

        #print cursor.rowcount

        for i in xrange(cursor.rowcount):
            idmd5, start, stop, KeyL = cursor.fetchone()
            #print start, stop

        # disconnect from server

        Status = 'Going'
        sql2 = "UPDATE md5 SET Done = '%s' WHERE idmd5 = %d" % (Status, idmd5)

        cursor.execute(sql2)
        db.commit()

        #Print SQL Statement
        #print sql2
        db.close()
        return start, stop, KeyL, idmd5


def hash():
    listme = getrec()
    db = MySQLdb.connect("nvidia1-crunchy", "root", "root", "hash")
    cursor = db.cursor()

    y = 0
    k = listme[2]
    error = 0
    start = listme[0]
    end = listme[1]
    TotalKeys = listme[1] - listme[0]
    keyspace = (ascii_letters + digits + punctuation)
    Keyspace2 = combinations_with_replacement(keyspace, listme[2])

    for x in islice(Keyspace2, start, end):
        joined = MySQLdb.escape_string(''.join(x))
        joined2 = (''.join(x))
        hexed = hashlib.md5(joined2).hexdigest()

        sql = "INSERT INTO table_%c(Hash, Plaintext) VALUES ('%s', '%s')" \
                % (hexed[0], hexed, joined)
        TotalKeys = TotalKeys - 1

        try:
            cursor.execute(sql)
            db.commit()
            print "Added entry number:", y, hexed[0:4], joined, TotalKeys
            y = y + 1
        except:
            print "Error on:", hexed, joined, TotalKeys
            db.rollback()
            sqlerror = "INSERT INTO error(Hash, Plaintext) VALUES \
                    ('%s', '%s')" % (hexed, joined)
            cursor.execute(sqlerror)
            db.commit()
            error = error + 1

    print "Key Space", k, "Combinations", y, "Number of Errors", error
    Status = "Done"
    sql3 = "UPDATE md5 SET Done = '%s' WHERE idmd5 = %d" % (Status, listme[3])
    print sql3
    cursor.execute(sql3)
    db.commit()
    db.close()
    print listme[0], listme[1], k

if __name__ == "__main__":
    x = 0
    while x <= 100:
        hash()
        x = x + 1